Ansible 2.0の新機能 Docker Connection Pluginを使ってDockerコンテナの構成管理をしてみた
はじめに
藤本です。
※ 本ブログ執筆時点ではAnsible 2.0はrc3です。GAリリース時にこのブログの通りにいかないことがあるかもしれませんのでご注意ください。
概要
Ansible 2.0からDockerのConnection Pluginが追加されました。Ansible 1.x系では標準モジュールだけでDockerコンテナをリモートから構成管理したい場合、コンテナ内でsshdを起動して、SSHポートをDockerホストと紐付けたりする必要があり、エージェントレス(ホストの構成を変えずに)が特徴のAnsibleとしては微妙な感じでした。Ansible 2.0で追加されたDockerのConnection Pluginを利用すれば、Docker Remote APIを利用したコンテナのプロビジョニングが可能となりました。Ansible実行環境からDockerホストへRemote APIを実行できる環境であれば、Dockerコンテナでsshdを起動しておく必要がありません。
今回はOSX上のVirtualBox上のDockerホスト(Docker Toolbox)に対して、ansible-playbookでWEBサーバをプロビジョンすることを目標します。
Docker Connection Plugin
Docker Connection Pluginはソースコードをザッと目を通した限り、ファイル転送にdocker cp
、コマンド実行をdocker exec
で実行しているようです。インベントリファイルではDockerホストを指定するのではなく、コンテナ名を指定します。そのためデフォルトではローカルホスト上のDockerコンテナに対して、処理を実行します。リモートホスト上のDockerコンテナに対して処理を実行したい場合、環境変数のDOCKER_HOST
でリモートホストを指定する必要があります。
環境
- Ansible実行環境
- OS : OSX
- Python : 2.7.10
- Ansible : v2.0.0-0.8.rc3
- Dockerホスト
- IPアドレス : 192.168.99.100
- on VirtualBox on OSX(Docker Toolboxにより構築)
やってみた
ansibleインストール
今回は2.0系を利用したいのでpip install ansible
ではなく、githubから最新版のリリースをインストールします。
$ pip install git+https://github.com/ansible/ansible.git Collecting git+https://github.com/ansible/ansible.git Cloning https://github.com/ansible/ansible.git to /var/folders/vp/2b51_dy91r3b5bbjsv1lbj4c0000gq/T/pip-nNfLOk-build Collecting paramiko (from ansible==2.1.0) Using cached paramiko-1.16.0-py2.py3-none-any.whl Collecting jinja2 (from ansible==2.1.0) Using cached Jinja2-2.8-py2.py3-none-any.whl Collecting PyYAML (from ansible==2.1.0) Requirement already satisfied (use --upgrade to upgrade): setuptools in /Users/fujimoto.shinji/.pyenv/versions/ansible/lib/python2.7/site-packages (from ansible==2.1.0) Collecting pycrypto>=2.6 (from ansible==2.1.0) Collecting ecdsa>=0.11 (from paramiko->ansible==2.1.0) Using cached ecdsa-0.13-py2.py3-none-any.whl Collecting MarkupSafe (from jinja2->ansible==2.1.0) Installing collected packages: ecdsa, pycrypto, paramiko, MarkupSafe, jinja2, PyYAML, ansible Running setup.py install for ansible Successfully installed MarkupSafe-0.23 PyYAML-3.11 ansible-2.1.0 ecdsa-0.13 jinja2-2.8 paramiko-1.16.0 pycrypto-2.6.1 $ pip list ansible (2.1.0) ecdsa (0.13) Jinja2 (2.8) MarkupSafe (0.23) paramiko (1.16.0) pip (7.1.0) pycrypto (2.6.1) PyYAML (3.11) setuptools (18.0.1) wheel (0.24.0)
ansibleがインストールされました。(なぜか2.1.0と表示される。。。)
環境変数設定
Docker Remote APIを外部ホストに実行したい場合、dockerコマンドのオプションで指定可能ですが、Docker Connection Pluginではオプション指定することができません。その代わりに環境変数に設定することで指定が可能です。Dockerホスト、TLSの有効化、およびSSH鍵関連パスを環境変数に設定します。
export DOCKER_TLS_VERIFY="1" export DOCKER_HOST="tcp://192.168.99.100:2376" export DOCKER_CERT_PATH="/Users/fujimoto.shinji/.docker/machine/machines/docker01"
ちなみに以下のコマンドでも同様の設定が可能です。
$ eval "$(docker-machine env docker01)"
Remote APIの接続確認を実施します。
$ docker info Containers: 1 Images: 5 Server Version: 1.9.1 Storage Driver: aufs Root Dir: /mnt/sda1/var/lib/docker/aufs Backing Filesystem: extfs Dirs: 7 Dirperm1 Supported: true Execution Driver: native-0.2 Logging Driver: json-file Kernel Version: 4.1.13-boot2docker Operating System: Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015 CPUs: 1 Total Memory: 1.956 GiB Name: default ID: 6E4I:7UKE:4RFA:HPFR:NJSN:ASG4:IRZI:J7DY:JMDZ:52XW:CCZH:UFJ2 Debug mode (server): true File Descriptors: 12 Goroutines: 18 System Time: 2015-12-24T06:45:56.410777786Z EventsListeners: 0 Init SHA1: Init Path: /usr/local/bin/docker Docker Root Dir: /mnt/sda1/var/lib/docker Labels: provider=virtualbox
情報取れました。接続できています。
インベントリファイルの作成
インベントリファイルにはDockerコンテナ作成用にDockerホスト、Dockerコンテナのプロビジョニング用にコンテナID、もしくはコンテナ名を指定します。今回はコンテナ名で指定します。
$ vi hosts --- [docker_host] docker01 [container] web01 --- $ vi ssh_config --- Host docker01 HostName 192.168.99.100 User docker UserKnownHostsFile /dev/null IdentityFile ~/.docker/machine/machines/docker01/id_rsa StrictHostKeyChecking no --- $ vi ansible.cfg --- [defaults] inventory = hosts [ssh_connection] ssh_args = -F ssh_config scp_if_ssh = True ---
Dockerホストへ接続確認します。
$ ansible -i hosts docker01 -m ping docker01 | FAILED! => { "changed": false, "failed": true, "module_stderr": "", "module_stdout": "sh: /usr/bin/python: not found\r\n", "msg": "MODULE FAILURE", "parsed": false }
boot2dockerのOSイメージはpythonがインストールされていない!!というかこのOSは何者?
・・・調べたら、Tiny Core LinuxというOSらしいです。エクステンションと呼ばれるパッケージをtce-loadコマンドでインストール出来るようです。
$ ssh -F ssh_config docker01 Warning: Permanently added '192.168.99.100' (RSA) to the list of known hosts. ## . ## ## ## == ## ## ## ## ## === /"""""""""""""""""\___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\_______/ _ _ ____ _ _ | |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __ | '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__| | |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ | |_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_| Boot2Docker version 1.9.1, build master : cef800b - Fri Nov 20 19:33:59 UTC 2015 Docker version 1.9.1, build a34a1d5 docker@docker01:~$ tce-load -wi python python.tcz.dep OK tk.tcz.dep OK readline.tcz.dep OK Downloading: libffi.tcz Connecting to repo.tinycorelinux.net (89.22.99.37:80) libffi.tcz 100% |**************************************************************************************************************************************| 16384 0:00:00 ETA libffi.tcz: OK (略) Downloading: python.tcz Connecting to repo.tinycorelinux.net (89.22.99.37:80) python.tcz 100% |*******************************************************************************************************************************************************************************************************************************| 7980k 0:00:00 ETA python.tcz: OK docker@docker01:~$ python --version Python 2.7.10 docker@docker01:~$ curl https://bootstrap.pypa.io/get-pip.py | sudo python - % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1379k 100 1379k 0 0 1831k 0 --:--:-- --:--:-- --:--:-- 1829k Collecting pip Downloading pip-7.1.2-py2.py3-none-any.whl (1.1MB) 100% |################################| 1.1MB 401kB/s Collecting setuptools Downloading setuptools-19.1.1-py2.py3-none-any.whl (463kB) 100% |################################| 466kB 774kB/s Collecting wheel Downloading wheel-0.26.0-py2.py3-none-any.whl (63kB) 100% |################################| 65kB 4.9MB/s Installing collected packages: pip, setuptools, wheel Successfully installed pip-7.1.2 setuptools-19.1.1 wheel-0.26.0 docker@docker01:~$ sudo pip install docker-py Collecting docker-py Downloading docker-py-1.6.0.tar.gz (63kB) 100% |################################| 65kB 2.2MB/s Collecting requests>=2.5.2 (from docker-py) Downloading requests-2.9.1-py2.py3-none-any.whl (501kB) 100% |################################| 503kB 748kB/s Collecting six>=1.4.0 (from docker-py) Downloading six-1.10.0-py2.py3-none-any.whl Collecting websocket-client>=0.32.0 (from docker-py) Downloading websocket_client-0.34.0.tar.gz (193kB) 100% |################################| 196kB 1.8MB/s Building wheels for collected packages: docker-py, websocket-client Running setup.py bdist_wheel for docker-py Stored in directory: /root/.cache/pip/wheels/e6/d9/a1/fe57c3e479387975813b221e7f01dcaa0f73e9149744472c71 Running setup.py bdist_wheel for websocket-client Stored in directory: /root/.cache/pip/wheels/c2/af/03/d3899019a2100d8b39625e578e8680f444096278d16b7dc4a4 Successfully built docker-py websocket-client Installing collected packages: requests, six, websocket-client, docker-py Successfully installed docker-py-1.6.0 requests-2.9.1 six-1.10.0 websocket-client-0.34.0 docker@docker01:~$ sudo ln -s /usr/local/bin/python /usr/bin/python
Pythonがインストールされました。ついでにpip、docker-pyをインストールして、pythonコマンドのパスにシンボリックリンク張りました。
もう一度、確認します。
$ ansible -i hosts docker01 -m ping docker01 | SUCCESS => { "changed": false, "ping": "pong" }
接続できました。ちなみにこの接続はDockerホストへの接続なので、まだ今回の主役のDocker Connection Pluginは関係ありません。SSH Connection Pluginによる接続です。
Playbook作成
Dockerコンテナの作成とプロビジョニングを一つのPlaybookにまとめて記述します。
まずはDockerコンテナの作成部分です。コンテナのプロビジョニングはAnsibleに任せたいのでただ起動させるだけです。
$ vi site.yml --- - hosts: docker_hosts become: yes remote_user: docker tasks: - name: deploy centos container docker: image=centos:centos6 name=web01 ports=80:80 expose=80 tty=yes
実行してみます。
$ ansible-playbook site.yml PLAY *************************************************************************** TASK [setup] ******************************************************************* ok: [docker01] TASK [deploy centos container] ************************************************* changed: [docker01] PLAY RECAP ********************************************************************* docker01 : ok=2 changed=1 unreachable=0 failed=0
コンテナが起動していることを確認してみます。
docker@docker01:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6636521e80f0 centos:centos6 "/bin/bash" 3 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp web01
起動していますね。
ここからが主題です。
先ほどのPlaybookにコンテナへの設定内容を追記します。Docker Connection Pluginを利用する設定としてはconnection: docker
を指定するだけです。コンテナの設定内容はシンプルでhttpd、filebeatをインストールして、index.html、filebeatの設定ファイルを置き換えて、サービスを起動するだけです。
$ vi site.yml --- - hosts: containers connection: docker # ここだけ tasks: - name: install packages yum: name={{item}} state=installed with_items: - httpd - "https://download.elastic.co/beats/filebeat/filebeat-1.0.1-x86_64.rpm" - name: copy filebeat.yml copy: src=filebeat.yml dest=/etc/filebeat/filebeat.yml backup=yes - name: start services service: name={{item}} enabled=yes state=started with_items: - httpd - filebeat
それではPlaybookを実行してみましょう。
$ ansible-playbook site.yml PLAY *************************************************************************** TASK [setup] ******************************************************************* ok: [docker01] TASK [deploy centos container] ************************************************* ok: [docker01] PLAY *************************************************************************** TASK [setup] ******************************************************************* ok: [web01] TASK [install packages] ******************************************************** changed: [web01] => (item=[u'httpd', u'https://download.elastic.co/beats/filebeat/filebeat-1.0.1-x86_64.rpm']) TASK [copy index.html] ********************************************************* changed: [web01] TASK [copy filebeat.yml] ******************************************************* changed: [web01] TASK [start services] ********************************************************** changed: [web01] => (item=httpd) changed: [web01] => (item=filebeat) PLAY RECAP ********************************************************************* docker01 : ok=2 changed=0 unreachable=0 failed=0 web01 : ok=4 changed=4 unreachable=0 failed=0
Webアクセスしてみます。
$ cat index.html index page on docker container $ curl 192.168.99.100 index page on docker container
コピーしたindex.htmlの内容が返ってきました。
まとめ
いかがでしたでしょうか。
今回の主題ではないところで躓いてしまって、伝えたい内容がブレブレになった気もしますが、、、今まではDockerコンテナの構築はDockerfile、ツールを利用したい人はPackerといったところが主流だったでしょうか。ただプロビジョニングツールとしてはAnsibleを利用している方も多いと思います。Docker Connection Pluginの導入により、DockerコンテナのプロビジョニングにAnsibleを採用するケールも増えるのではないでしょうか。